<template>
  <jb-page :show-header="false">
    <div class="chat-container">
      <div class="chat-layout">
        <div class="chat-sidebar">
          <div class="chat-search" style="display: flex;align-items: center">
            <n-input v-model:value="keywords" placeholder="快速搜索..."/>
            <jb-btn style="margin-left: 8px" type="primary" icon="" @click="handleAddChat">新建聊天</jb-btn>
          </div>

          <div class="chat-list" ref="chatListRef" @scroll="handleSessionScroll">
            <div v-for="(chat,index) in chats" :key="chat.id" class="chat-item"
                 :class="{ active: activeChatId === chat.id }" @click="activeChatId = chat.id">
              <div class="chat-item-content">
                <div class="chat-item-title">{{ chat.name || '新的会话' }}</div>
                <div class="chat-item-time">{{ chat.createTime || '-' }}</div>
              </div>
              <div class="chat-actions">
                <jb-btn :icon="Icons.EDIT" text type="warning" circle :modalComponent="ChatEdit"
                        modalTitle="编辑会话名称" :modalComponentProps="{id:chat.id}" modalWidth="600px"
                        @modalYesClick="handleChatNameEdit"></jb-btn>
                <jb-btn :icon="Icons.DELETE" text type="error" circle :confirmText="'确认删除该会话？'"
                        :url="`/aiAppSession/delete/${chat.id}`"
                        @success="handleDeleteChat(index)"></jb-btn>
              </div>
            </div>
            <div v-if="chatPageState.loading" class="loading-more">
              <n-spin size="small"/>
              <span>加载中...</span>
            </div>
          </div>
        </div>
        <div v-if="!activeChatId"
             style="display: flex; justify-content: center;align-items: center;flex:1;font-size: 36px;font-weight: 500;color:#d5d5d5">
          请先创建或选择一个会话
        </div>
        <div class="chat-main" v-show="activeChatId">

          <div class="system-role">
						<textarea v-model="currentChat.config.llmConfig.systemRole"
                      placeholder="输入系统角色设定..."></textarea>
          </div>

          <div class="chat_panel" style="position: relative" ref="chatContainer">

          </div>

        </div>
      </div>


    </div>
    <div v-if="showAISetting"
         style="display:flex;flex-direction:column;position: absolute;bottom: 140px;right: 80px;width: 360px;background-color:#FFF;border-radius: 16px;box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.1);padding: 18px 16px">
      <div
          style="width: 100%;display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #ccc;padding: 10px">
        <span style="font-size: 18px">AI设置</span>
        <div style="cursor: pointer" @click="showAISetting=false">
          <jb-icon icon="iconamoon:close-bold" style="font-size: 20px;color: #333"></jb-icon>
        </div>

      </div>

      <n-form style="margin-top: 24px" ref="formRef" :model="currentChat.config.llmConfig" label-placement="top"
              label-width="120" require-mark-placement="right-hanging">
        <n-form-item label="选择AI模型" path="name">
          <jb-select url="aiResource/listAllEnabledType" labelField="name" placeholder="请选择AI模型"
                     valueField="sn" v-model:value="currentChat.config.llmConfig.model"></jb-select>
        </n-form-item>
        <n-form-item label="MaxToken值" path="sn">
          <div class="flex-col">
            <n-input-number round style="width: 100%" v-model:value="currentChat.config.llmConfig.maxTokens"
                            placeholder="请输入MaxToken值" max="8192">
              <template #suffix>
                tokens
              </template>
            </n-input-number>
            <span style="font-size: 12px">范围: 1-8192</span>
          </div>

        </n-form-item>
        <n-form-item label="Temperature" path="">
          <n-input-number round style="width: 100%" v-model:value="currentChat.config.llmConfig.temperature"
                          :precision="2" placeholder="请输入Temperature值">
          </n-input-number>
        </n-form-item>
        <n-form-item label="Top P" path="">
          <div style="display: flex;flex-direction: column">
            <n-slider v-model:value="currentChat.config.llmConfig.topP" :step="0.1" :max="1"/>
            <span
                style="font-size: 12px">调节句子生成的多样性，值越大生成的内容越丰富多样，但它和Temperature只能设置一个</span>
          </div>
        </n-form-item>
        <n-form-item label="Top K" path="">
          <div style="display: flex;flex-direction: column">
            <n-input-number round style="width: 100%" :precision="0"
                            v-model:value="currentChat.config.llmConfig.topK" placeholder="请输入TopK值"
                            max="100">
            </n-input-number>
            <span
                style="font-size: 12px">限制每次生成时考虑的词汇数量，值越大创造性越强。该选项不是所有大模型都支持。</span>
          </div>
        </n-form-item>

        <div style="display: flex;justify-content: space-between;width: 100%">
          <span style="font-size: 16px">开启上下文</span>
          <n-switch size="large" v-model:value="currentChat.config.llmConfig.useContext"></n-switch>
        </div>
      </n-form>
    </div>


  </jb-page>
</template>

<script setup>
import {
  onActivated,
  onBeforeUnmount, onDeactivated,
  onMounted,
  reactive,
  ref,
  watch
} from 'vue';
import {
  Icons
} from '@/constants'
import {
  JBoltApi
} from "@/service/request/index.js";
import {
  debounce
} from 'lodash-es';
import ChatEdit from './components/chat-edit.vue'
import markdownit from 'markdown-it'
import AiChat from '@/components/_builtin/jb-ai-chat/index.js'
import {
  storeToRefs
} from "pinia";
import {
  useWebSocketStore
} from "@/stores/websocket.js";
import { useMessage } from 'naive-ui'


const md = markdownit({
  html: true,
  breaks: true,
  linkify: true,
  typographer: true
});

const defaultAIConfig = {
  systemRole: '',
  maxTokens: 2000,
  topP: 0,
  topK: 0,
  model: '',
  useContext: true,
  temperature: 0.5
}
const message = useMessage()


//--------------- 左侧session列表
const appId = ref(1)
const keywords = ref('');
const chatListRef = ref(null);
const activeChatId = ref(null);
//当前会话聊天配置

const currentChat = ref({
  id: '',
  name: '',
  config: {
    llmConfig: {
      systemRole: ''
    }
  }
})
const chats = ref([]);
const chatPageState = reactive({
  pageSize: 20,
  startId: null,
  hasMore: true,
  loading: false,
});
// 监听搜索关键词变化
watch(keywords, debounce((val) => {
  resetChatList()
  loadChatList(true);
}, 300));


function resetChatList() {
  chatPageState.startId = null;
  chatPageState.hasMore = true;
  chatPageState.loading = false;
  chats.value = [];
}

async function loadChatList(isFirst) {
  // console.log("调用")
  if (chatPageState.loading || chatPageState.hasMore == false) return;
  // console.log("调用22")
  chatPageState.loading = true;
  try {
    const {
      result
    } = await JBoltApi.get('/aiAppSession/getListByPage', {
      pageSize: chatPageState.pageSize,
      startId: chatPageState.startId,
      keywords: keywords.value,
      appId: appId.value, //内置应用
    });
    let {
      list,
      totalPage
    } = result.data;

    list = list ?? [];
    chatPageState.hasMore = list.length == chatPageState.pageSize;

    chatPageState.startId = list[list.length - 1]?.id;
    chats.value.push(...list)

    if (isFirst) {
      console.log("新的值")
      activeChatId.value = chats.value[0]?.id
    }
  } catch (error) {
    console.error('加载聊天列表失败:', error);
  } finally {
    chatPageState.loading = false;
  }
}

function handleDeleteChat(index) {
  if (activeChatId.value == chats.value[index].id) {
    activeChatId.value = null;
  }
  chats.value.splice(index, 1);


}

function handleChatNameEdit({
                              componentRef,
                              close
                            }) {
  componentRef.submit((formData) => {
    close()
    let index = chats.value.findIndex(item => item.id == formData.id)
    if (index >= 0) {
      chats.value[index].name = formData.name
    }
  })
}

function handleAddChat() {
  JBoltApi.post('/aiAppSession/add', {
    name: '新的会话',
    appId: appId.value, //内置appId
    config: {
      "llmConfig": defaultAIConfig
    }
  }).then(() => {
    resetChatList();
    loadChatList(true);
  });
}

//更新session
function handleUpdateSessionName(sessionId, msg) {
  var name = msg.substring(0, 20);
  JBoltApi.post('/aiAppSession/update', {
    name: name,
    id: sessionId,
    appId: appId.value
  }).then(() => {
    const itemToUpdate = chats.value.find(item => item.id === sessionId);
    if (itemToUpdate) {
      itemToUpdate.name = name;
    }
  });
}

// 处理滚动事件
function handleSessionScroll(e) {
  const {
    scrollHeight,
    scrollTop,
    clientHeight
  } = e.target;
  // 距离底部100px时加载更多
  if (scrollHeight - scrollTop - clientHeight < 100 && !loading.value && hasMore.value) {
    loadChatList();
  }
}


//-------------右侧聊天区域
const chatContainer = ref(null);
const chatInstance = ref(null);
const chatState = ref({
  pageSize: 20,
  hasMore: true,
})
const showAISetting = ref(false)

const webSocketStore = storeToRefs(useWebSocketStore())
watch(() => webSocketStore.ws.value, () => {
  console.debug("websock重连")
  if (chatInstance.value) {
    chatInstance.value.updateWebSocket(webSocketStore.ws.value)
  }
})

watch(() => chatContainer.value, (newV) => {
  console.debug("chatContainer watch...")
  //dom初始化好了
  if (newV && activeChatId.value && !chatInstance.value) {
    loadChatInstance()
  }
})


watch(() => activeChatId.value, (newV) => {
  if (newV) {
    if (chatInstance.value) {
      chatInstance.value.destroy();
    }
    JBoltApi.get(`/aiAppSession/getById/${activeChatId.value}`).then(res => {
      currentChat.value = {
        ...res.result.data,
        hasMsg: false
      }
      watchConfigChange(currentChat.value)
    })
    if (chatContainer.value) {
      chatState.value = {
        pageSize: 20,
        hasMore: true
      }
      // console.log("+++++++")
      loadChatInstance()
    }
  }

})


function loadChatInstance() {
  //初始化aichat
  chatInstance.value = new AiChat(chatContainer.value, {
    // websocketUrl: 'ws://192.168.31.118:8013/ws',
    websocketInstance: webSocketStore.ws.value,
    app: appId.value,
    sessionId: activeChatId.value,
    global: null,
    showAvatar: false,
    onMsgReceive: (data) => {

    },
    onMsgSend: (msg) => {
      if (currentChat.value.hasMsg == false) {
        //调用更新sessinoName的方法
        handleUpdateSessionName(currentChat.value.id, msg.data.content.text);
      }
    },
    onMsgToDelete: async (id) => {
      console.debug("删除消息", id)
      let {
        result
      } = await JBoltApi.get(`/aiAppMessage/delMsgById/${id}`)
      console.log(result,"----")
      if (result.code == 0) {
        message.success("删除成功");
        return true;
      } else {
        message.error("删除失败");
        return false;
      }
    },
    onSettingClick: (chatInsence) => {
      showAISetting.value = !showAISetting.value
    },
    onMarkdownRender: (markdown) => {
      // console.log("开始渲染", markdown)
      return md.render(markdown);
    },
    onHistoryLoad: async (startId, global) => {
      console.log("++++加载历史记录...", startId, chatState.value.hasMore)
      console.log("activeChatId...", activeChatId.value)
      if (chatState.value.hasMore == false) return;
      let {
        result
      } = await JBoltApi.get('/aiAppMessage/getListByPage', {
        sessionId: activeChatId.value,
        startId,
        pageSize: chatState.value.pageSize,
      })

      let {
        list,
        totalPage
      } = result.data
      chatState.value.hasMore = chatState.value.pageSize == list?.length;
      console.debug("加载历史记录开始", list)
      if (!list || !list.length) {
        // console.log(currentChat.value.hasMsg)
        return false;
      }
      // console.debug("加载历史记录完成...", list)
      currentChat.value.hasMsg = true;
      return list.map(item => {
        return {
          id: item.id,
          flag: item.role == "user" ? item.id : item.linkId,
          data: {
            role: item.role,
            format: item.role == 'assistant' ? "markdown" : "",
            content: {
              text: item.content,
            },
            reference: item.reference,
            errorMsg: item.errorMsg,
          },

          createTime: item.createTime
        }
      })
    }
  })

}

let configMonitor = null;

function watchConfigChange(chat) {
  if (configMonitor != null) {
    configMonitor();
  }
  configMonitor = watch(() => chat.config.llmConfig, (newVal, oldVal) => {
    // console.log("AI配置变动：", newVal);
    JBoltApi.post('/aiAppConfig/updateConfig', {
      linkType: "session",
      linkId: chat.id,
      configType: "llmConfig",
      configValue: JSON.stringify(newVal)
    });
  }, {
    deep: true
  })
}


onMounted(() => {
  loadChatList(true);
});
onBeforeUnmount(() => {
  if (chatInstance.value) {
    chatInstance.value.destroy()
  }
})
onActivated(() => {
  if (!chatInstance.value && activeChatId.value) {
    chatState.value.hasMore = true
    loadChatInstance()
  }
  console.log("aiChat组件被激活,当前被选中的id:" + activeChatId.value)
})
onDeactivated(() => {
  if (chatInstance.value) {
    chatInstance.value.destroy()
    chatInstance.value = null;
  }
})
</script>

<style scoped lang="scss">
.chat-container {
  height: 100%;
  overflow: hidden;
}

.chat-layout {
  display: flex;
  height: 100%;
  background-color: #fff;
}

.chat-sidebar {
  width: 300px;
  border-right: 1px solid #eee;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.chat-search {
  padding: 12px;
  border-bottom: 1px solid #eee;
  flex-shrink: 0;
}

.chat-list {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
}

.chat-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.chat-messages {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
}

.chat-input {
  border-top: 1px solid #eee;
  padding: 20px;
  background: #fff;
}

.chat-item {
  padding: 12px;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.3s;
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.chat-item:hover {
  background-color: rgba(0, 0, 0, 0.05);
}

.chat-item.active {
  background-color: rgba(0, 0, 0, 0.05);

  .chat-actions {
    opacity: 1;
  }
}

.chat-item-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.chat-item-title {
  font-size: 14px;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-item-time {
  font-size: 12px;
  color: #999;
}

.chat-actions {
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.3s;
}

.chat-item:hover .chat-actions {
  opacity: 1;
}

.chat-actions :deep(.n-button) {
  padding: 4px;
}

.system-role {
  padding: 1rem;
}

.system-role textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgb(215 216 218);
  border-radius: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  resize: none;
  height: 60px;
  transition: height 0.3s ease;
  outline: none;
}

.system-role textarea:focus {
  border-color: #333;
}

.system-role textarea:hover {
  height: 120px;
}

.loading-more {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  gap: 8px;
  color: #999;
  font-size: 12px;
}

.chat_panel {
  flex: 1;
  overflow: hidden;
  padding: 1em;
}
</style>